use halo_model::GroupVersionKind;
use salvo::{
    async_trait, http::ParseError, prelude::EndpointOutRegister, writing::Json, Depot, Request,
    Response, Writer,
};
use thiserror::Error;
use tracing::error;

#[derive(Error, Debug)]
pub enum AppError {
    #[error("error:`{0}`")]
    AnyHow(#[from] anyhow::Error),

    #[error("http::ParseError:`{0}`")]
    ParseError(#[from] ParseError),

    #[error("sea_orm::DbErr:Error:`{0}`")]
    DbErr(#[from] sea_orm::DbErr),

    #[error("serde_json::Error:`{0}`")]
    SerdeErr(#[from] serde_json::Error),

    #[error("{0}")]
    DuplicateNameError(String),

    #[error("Scheme not found for {0}")]
    SchemeNotFoundErr(GroupVersionKind),

    #[error("Internal server error: {0}")]
    InternalServerError(String),

    #[error("{0}")]
    Err(String),
}

impl AppError {
    pub fn err(err: &str) -> AppError {
        return AppError::Err(err.to_string());
    }
}

pub type AppResult<T> = Result<T, AppError>;

#[async_trait]
impl Writer for AppError {
    async fn write(mut self, _req: &mut Request, _depot: &mut Depot, res: &mut Response) {
        res.render(Json(self.to_string()));
        error!("Internal AppError {}", self.to_string());
    }
}

impl EndpointOutRegister for AppError {
    fn register(_components: &mut salvo::oapi::Components, operation: &mut salvo::oapi::Operation) {
        operation
            .responses
            .insert("500".to_string(), salvo::oapi::Response::new("error"));
    }
}
